<?php
namespace  common\util;
/**
 * Lib_Curl HTTP请求封装类
 * @author ziyang.wu@corp.elong.com
 * @copyright www.elong.com
 * @version $Id: curl.php 336208 2015-08-14 07:19:18Z ziyang.wu $
 **/

class Curl {
    
    protected $_connectTimeout = 10010;
    
    protected $_timeout = 10010;
    
    protected $ch;
    
    protected $errCode;
    
    protected $errMsg;
    
    protected $httpCode;
    
    protected $response;
    
    //并行定义
    protected $multi_ch;
    
    protected $multi_handle = [];
    
    protected $multi_content = [];
    
    public function __construct($url = null){
        $this->ch = curl_init();
        $this->setOpt(CURLOPT_RETURNTRANSFER, 1);
        $this->setTimeOut($this->_timeout);
        $this->setConnectTimeOut($this->_connectTimeout);
        if($url){
            $this->setUrl($url);
        }
    }
    
    public function __destruct(){
        if( is_resource($this->ch) ){
            curl_close($this->ch);
        }
    }
    
    
    public function setOpt($option,$value){
        curl_setopt($this->ch, $option, $value);
    }
    
    //设置请求地址
    public function setUrl($url){
        $this->setOpt(CURLOPT_URL,$url);
    }
    
    //设置浏览器类型
    public function setUserAgent($ua){
        $this->setOpt(CURLOPT_USERAGENT,$ua);
    }
    
    //设置ReFerer地址
    public function setReferer($refer){
        $this->setOpt(CURLOPT_REFERER,$refer);
    }
    
    //设置Cookie数据
    public function setCookie($httpCookie){
        $this->setOpt(CURLOPT_COOKIE,$httpCookie);
    }
    
    //设置HTTP请求头信息
    public function setHeader(Array $httpHeader){
        $this->setOpt(CURLOPT_HTTPHEADER, $httpHeader);
    }
    
    //设置返回HTTP响应头信息
    public function setReturnHeader($returnHeader = true){
        $this->setOpt(CURLOPT_HEADER, $returnHeader);
    }
    
    //设置处理超时，单位毫秒
    public function setTimeOut($ms){
        $this->setOpt(CURLOPT_TIMEOUT_MS,$ms);
    }
    
    //设置连接超时，单位毫秒
    public function setConnectTimeOut($ms){
        $this->setOpt(CURLOPT_CONNECTTIMEOUT_MS,$ms);
    }
    
    //获取响应信息头的大小
    public function getHeaderSize(){
        return curl_getinfo($this->ch, CURLINFO_HEADER_SIZE);
    }
    
    //获取响应http状态码
    public function getHttpCode(){
        return curl_getinfo($this->ch, CURLINFO_HTTP_CODE);
    }
    
    //获取错误号
    public function getErrorCode(){
        return curl_errno($this->ch);
    }
    
    //获取错误信息
    public function getErrorMsg(){
        return curl_error($this->ch);
    }
    
    public function getResponse(){
        return $this->response;
    }
    
    //单进程处理
    private function singleExec(){
        $this->response = curl_exec($this->ch);
        $this->errCode = $this->getErrorCode();
        $this->errMsg = $this->getErrorMsg();
        $this->httpCode =  $this->getHttpCode();
        return $this->httpCode;
    }
    
    //发起单进程GET请求
    public function singleHttpGet(){
        return $this->singleExec();
    }
    
    //发起单进程POST请求
    public function singleHttpPost($params=[]){
        $this->setOpt(CURLOPT_POST, 1);
        $this->setOpt(CURLOPT_POSTFIELDS, $params);
        return $this->singleExec();
    }
    
    //关闭连接
    public function singleClose(){
        if( is_resource($this->ch) ){
            curl_close($this->ch);
        }
    }
    
    //多进程处理
    private function multiExec(){
        //执行批处理句柄
        $active = null;
        do {
            $mrc = curl_multi_exec($this->multi_ch, $active);
        } while ($mrc == CURLM_CALL_MULTI_PERFORM);
        
        while ($active && $mrc == CURLM_OK) {
            if(curl_multi_select($this->multi_ch) === -1){
                usleep(100);
            }
            do {
                $mrc = curl_multi_exec($this->multi_ch, $active);
            } while ($mrc == CURLM_CALL_MULTI_PERFORM);
        }
        
        //获取批处理内容
        foreach($this->multi_handle as $i => $ch){
            $content = curl_multi_getcontent($ch);
            $this->multi_content[$i] = curl_errno($ch) == 0 ? $content : '';
        }
        
        //移除批处理句柄
        foreach($this->multi_handle as $ch){
            curl_multi_remove_handle($this->multi_ch, $ch);
        }
        
        //关闭批处理句柄
        curl_multi_close($this->multi_ch);
    }
    
    
    //并发HTTP请求GET方式
    public function multiHttpGet(Array $url_array, $timeOut = 120){
        $result = ['code' => 0,'msg'=>'','data'=>null];
        if(empty($url_array)){
            $result['code'] = -3;
            $result['msg'] = 'url is empty';
            return $result;
        }
        
        //初始化curl multi对象
        $this->multi_ch = curl_multi_init();
        
        //添加curl 批处理会话
        foreach($url_array as $key => $url){
            $this->multi_handle[$key] = curl_init($url);
            curl_setopt($this->multi_handle[$key], CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($this->multi_handle[$key], CURLOPT_TIMEOUT, $timeOut);
            curl_setopt($this->multi_handle[$key], CURLOPT_HEADER, 0 );
            curl_multi_add_handle($this->multi_ch, $this->multi_handle[$key]);
        }
        
        //返回处理结果
        $this->multiExec();
        $result['data'] = $this->multi_content;
        return $result;
    }
    
    /**
     * POST方式并发HTTP请求
     *
     * @param array $url_array      url地址数组
     * $url_array = array(
     'http://www.elong.com/c1/act1',
     'http://www.elong.com/c2/act2',
     'http://www.elong.com/c3/act3'
     );
     *
     * @param array $url_params     Post的数据，同url数据key对应
     * $url_array = array(
     array('id'=>1,'name'=>1),
     array('id'=>1,'name'=>1),
     array('id'=>1,'name'=>1),
     );
     *
     *
     * @param int $timeOut 超时时间，适用于每个进程
     * @return array
     */
    public function multiHttpPost(Array $url_array, Array $url_params, $timeOut = 120){
        $result = ['code' => 0,'msg'=>'','data'=>null];
        if(empty($url_array)){
            $result['code'] = -1;
            $result['msg'] = 'url is empty';
            return $result;
        }
        
        if(!empty($url_params) && count($url_array) != count($url_params)){
            $result['code'] = -2;
            $result['msg'] = 'url and params not match';
            return $result;
        }
        
        //初始化curl multi对象
        $this->multi_ch = curl_multi_init();
        
        //添加curl 批处理会话
        foreach($url_array as $key => $url){
            $this->multi_handle[$key] = curl_init($url);
            curl_setopt($this->multi_handle[$key], CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($this->multi_handle[$key], CURLOPT_TIMEOUT, $timeOut);
            curl_setopt($this->multi_handle[$key], CURLOPT_POST, 1 );
            curl_setopt($this->multi_handle[$key], CURLOPT_HEADER, 0 );
            curl_setopt($this->multi_handle[$key], CURLOPT_POSTFIELDS, $url_params[$key]);
            curl_multi_add_handle($this->multi_ch, $this->multi_handle[$key]);
        }
        
        //返回处理结果
        $this->multiExec();
        $result['data'] = $this->multi_content;
        return $result;
    }
    
}
